package com.baidu.netdisk;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.Scriptable;

import com.xygood.netdisk.MainActivity;

import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import android.util.Base64;



public class BaiduClient {
	private static final String TAG = "BaiduClient";
	private static final String BDS_TOKEN_URL = "http://pan.baidu.com/disk/home?adapt=pc";
	private static final String GET_FILE_LIST_URL = "http://pan.baidu.com/api/list?channel=chunlei&clienttype=0&app_id=250528&web=1&showempty=0";
	private static final String BDS_TOKEN_KEY = "MYBDSTOKEN";
	private static final String BDS_SIGN1_KEY = "sign1";
	private static final String BDS_SIGN2_KEY = "sign2";
	private static final String BDS_SIGN3_KEY = "sign3";
	
	private static final String ORDER_BY_TIME = "time";
	private static final String ORDER_BY_NAME = "name";
	private static final String ORDER_BY_SIZE = "size";
	
	private String mCookie ;
	private String mBDSToken;
	
	private String mSign1;
	private String mSign2;
	private String mSign3;
	private String mEncodedSign;
	
	public BaiduClient(String cookie) {
		mCookie = cookie;
	}
	
	public List<BaiduListFileInfo> getFileList(String path) {
		return getFileList(path, 100, 1, ORDER_BY_TIME, true);
	}
	
	public List<BaiduListFileInfo> getFileList(String path, int countPerPage, int pageNumber, String ORDER_BY, boolean isDesc) { 
		StringBuilder builder = new StringBuilder(GET_FILE_LIST_URL);
		if (TextUtils.isEmpty(getBDSToken())) {
			return null;
		}
		
		builder.append("&bdstoken=" + mBDSToken);
		builder.append("&_="+System.currentTimeMillis());
		
		try {
			builder.append("&dir=" + URLEncoder.encode(path, "utf-8"));
		} catch (UnsupportedEncodingException e) {
			
			e.printStackTrace();
			return null;
		}
		
		builder.append("&num=" + countPerPage);
		builder.append("&page=" + pageNumber);
		builder.append("&order=" + ORDER_BY);
		
		if (isDesc) {
			builder.append("&desc=1");
		} else {
			builder.append("&asc=1");
		}

		//Log.d(TAG, "list url = " + builder.toString());
		
		HttpURLConnection conn = null;
		BufferedReader reader = null;
		try {
			conn = (HttpURLConnection) (new URL(builder.toString()).openConnection());
			
			conn.addRequestProperty("Cookie", mCookie);
			conn.addRequestProperty("Referer","http://pan.baidu.com/disk/home?adapt=pc");
			conn.addRequestProperty("X-Requested-With","XMLHttpRequest");
			
			reader = new BufferedReader(
					new InputStreamReader(conn
							.getInputStream()));
			
			String line = null;
			StringBuilder result = new StringBuilder(20480);
			while ((line = reader.readLine()) != null ) {
				result.append(line);
				//Log.d(TAG, "reader res = " + s);
			}
			
			JSONTokener jsonParser = new JSONTokener(result.toString());  
			JSONObject info = (JSONObject)jsonParser.nextValue();
			if (info.optInt("errno", -1) != 0) {
				return null;
			}
			
			JSONArray array = (JSONArray)info.optJSONArray("list");
			if (array == null) {
				return null;
			}
			
			List<BaiduListFileInfo> fileInfoList = new ArrayList<BaiduListFileInfo>(array.length());
			for (int i=0; i<array.length(); ++i) {
				JSONObject obj = array.optJSONObject(i);
				fileInfoList.add(new BaiduListFileInfo(obj));
			}
			return fileInfoList;
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();
			}
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		return null;
	}
	
	synchronized private String getBDSToken() {
		if (mBDSToken == null) {
			if (TextUtils.isEmpty(mCookie)) {
				return null;
			}
			
			HttpURLConnection conn = null;
			BufferedReader reader = null;
			try {
				URL url = new URL(BDS_TOKEN_URL);
				conn = (HttpURLConnection) url
						.openConnection();
				conn.addRequestProperty("Cookie",
						mCookie);
				reader = new BufferedReader(
						new InputStreamReader(conn
								.getInputStream()));
				
				String line = null;
				StringBuilder result = new StringBuilder(20480);
				while ((line = reader.readLine()) != null ) {
					result.append(line);
					Log.d(TAG, "reader res = " + line);
				}
				
				String regex1 = "\\byunData\\.(\\w+)\\s*=\\s*\"([^\"]+)\"";
				String regex2 = "\\byunData\\.(\\w+)\\s*=\\s*\'([^\']+)\'";
				
				Matcher matcher = Pattern.compile(regex1).matcher(result);
				
				Map<String, String> yunMap = new HashMap<String, String>();
				while(matcher.find()) {
					Log.d(TAG, "reader key = " + matcher.group(1) + "value = " + matcher.group(2));
					yunMap.put(matcher.group(1), matcher.group(2));
					if (matcher.group(1).equals(BDS_TOKEN_KEY)) {
						mBDSToken = matcher.group(2);
						break;
					}
				}
				
				matcher = Pattern.compile(regex2).matcher(result);
				
				while(matcher.find()) {
					Log.d(TAG, "reader key = " + matcher.group(1) + "value = " + matcher.group(2));
					yunMap.put(matcher.group(1), matcher.group(2));
					if (matcher.group(1).equals(BDS_TOKEN_KEY)) {
						mBDSToken = matcher.group(2);
						break;
					}
				}
				
				mBDSToken = yunMap.get(BDS_TOKEN_KEY);
				mSign1 = yunMap.get(BDS_SIGN1_KEY);
				mSign2 = yunMap.get(BDS_SIGN2_KEY);
				mSign3 = yunMap.get(BDS_SIGN3_KEY);
				
				Log.d(TAG, "mSign1 = " +mSign1);
				Log.d(TAG, "mSign2 = " +mSign2);
				Log.d(TAG, "mSign3 = " +mSign3);
				
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (conn != null) {
					conn.disconnect();
				}
				if (reader != null) {
					try {
						reader.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		return mBDSToken;
	}
	
	
	synchronized public String getSign() {
		if (mEncodedSign == null) {
			String  result = mSign2;
			Context context = Context.enter();
			context.setOptimizationLevel(-1);
			Scriptable scope = context.initStandardObjects();
			
			
			Matcher matcher = Pattern.compile("\\\\x(\\w\\w)").matcher(mSign2);
			
			StringBuilder builder = new StringBuilder();
			int offset = 0;
			while (matcher.find()) {
				builder.append(mSign2.toCharArray(), offset, matcher.start()-offset);
				builder.append((char)(Integer.parseInt(matcher.group(1), 16)));
				offset = matcher.end();
			}
			
			builder.append(mSign2.toCharArray(), offset, mSign2.length()-offset);
			
			//Log.d(TAG, "builder = " + builder.toString());
			//builder = new StringBuilder("function (a, b) { return a };");
			Function function = context.compileFunction(scope, builder.toString(), "sign2", 0, null);
			Object scriptSign1 = context.javaToJS(mSign1, scope);
			Object scriptSign3 = context.javaToJS(mSign3, scope);
			//scope.put("sign2", scope, obj);
			//Object sign2 = scope.get("sign2", scope);

			if (function != null) {
				result = context.toString(function.call(context, scope, scope, new Object[] {scriptSign3, scriptSign1}));
			}
			
			try {
				mEncodedSign = new String(Base64.encode(result.getBytes("iso8859-1"), Base64.DEFAULT), "iso8859-1");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}	
			
			try {
				Log.d(TAG, "mEncodedSign = " + mEncodedSign + ", result=" + result  + "result.length=" + result.getBytes("iso8859-1").length);
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} 
		return mEncodedSign;

	}
	
	synchronized public String getDownloadUrl(long ... fileIds) {
		if (fileIds == null ||fileIds.length<0) {
			return null;
		}
		
		if (TextUtils.isEmpty(mCookie)) {
			return null;
		}
		
		String fileList = "[" + fileIds[0];
		for (int i=1; i<fileIds.length; ++i) {
			fileList += ","+ fileIds[i];
		}
		fileList += "]";
		
		try {
			StringBuilder urlBuilder = new StringBuilder("http://pan.baidu.com/api/download?sign=" + URLEncoder.encode(getSign(), "utf8"));
			urlBuilder.append("&timestamp=" + System.currentTimeMillis());
			urlBuilder.append("&fidlist=" +  URLEncoder.encode(fileList, "utf8"));
			urlBuilder.append("&type=dlink");
			urlBuilder.append("&bdstoken="+getBDSToken());
			urlBuilder.append("&channel=chunlei&clienttype=0&web=1&app_id=250528");
			Log.d(TAG, "getDownloadUrl url = " + urlBuilder.toString());
			URL url = new URL(urlBuilder.toString());
			HttpURLConnection conn = (HttpURLConnection) url
					.openConnection();
			conn.addRequestProperty("Cookie",
					mCookie);
			
			conn.addRequestProperty("Referer","http://pan.baidu.com/disk/home?adapt=pc");
			conn.addRequestProperty("X-Requested-With","XMLHttpRequest");
			
			BufferedReader reader = new BufferedReader(
					new InputStreamReader(conn
							.getInputStream()));
			
			String line = null;
			StringBuilder result = new StringBuilder(20480);
			while ((line = reader.readLine()) != null ) {
				result.append(line);
				Log.d(TAG, "getDownloadUrl res = " + line);
			}
			return result.toString();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	
}
